
import os
import sysObjs
import json 
import socket
import threading
import time
from queue import Queue
import requests
import math
import pymssql
from DBUtils.PooledDB import PooledDB

# pip3 install -i https://pypi.doubanio.com/simple paho-mqtt
from paho.mqtt import client as mqtt_client
import random
###
# pip install pymysql
# pip install DBUtils==1.3  --- 特别要注意
class TMssqlConnection:
    def __init__(self) -> None:
        self.key = ""

        self.host = "meeting.xmgkfw.com"
        self.port = 42049
        self.userName = "sa"
        self.pwd = "Hhuc1115"
        self.dbName = "modbusTcp"
        self.maxNum = 10
        self.minNum = 1
        self.sqlPath = ""

        self.pool = None

    def setConfig(self, host, port, uid, pwd, db, sqlPath):
        self.host = host
        self.port = port
        self.uid = uid
        self.pwd = pwd
        self.dbName = db
        self.sqlPath = sqlPath

    def getConn(self):
        conn = None
        try:
            if self.pool == None:
                self.pool = PooledDB(
                    creator=pymssql,
                    mincached=1,
                    maxcached=10,
                    host=self.host,
                    port=self.port,
                    database=self.dbName,
                    user=self.userName,
                    password=self.pwd
                )
            conn = self.pool.connection()
            # conn.setAutoCommit(True)
        except Exception as er:
            print(er)
        return conn

    def getSql(self, sqlKey):
        res = ""
        try:
            filePath = os.path.join(self.sqlPath, sqlKey)
            if filePath.find(".txt") < 0:
                filePath = filePath + ".txt"
            if os.path.exists(filePath):
                with open(filePath, "r", encoding='utf-8') as f:
                    res = f.read()
            else:
                print('sqlKey(' + sqlKey + ') is error.')
        except Exception as er:
            print(er)
        return res

    def query(self, sql, params):
        res = {}
        rs = None
        try:
            conn = self.getConn()
            cursor = conn.cursor(as_dict=True)
            if params != None:
                cursor.execute(sql, params)
            else:
                cursor.execute(sql)

            rsList = []

            if cursor.description != None:
                rs = cursor.fetchall()
                rsList.append(list(rs))
                while cursor.nextset():
                    rs = cursor.fetchall()
                    rsList.append(list(rs))
                if len(rsList) == 1:
                    res = rsList[0]
                else:
                    res = rsList
                # res = list(rs)
            else:
                res = {
                    "rowNum": cursor.rownumber,
                    "rowCount": cursor.rowcount,
                    "newId": cursor.lastrowid
                }
            cursor.close()
            cursor = None
            conn.close()
            conn = None
        except Exception as er:
            print(er)
        return res

    def queryBySqlKey(self, sqlKey, params):
        rs = None
        try:
            sql = self.getSql(sqlKey)
            if sql != "":
                rs = self.query(sql, params)
        except Exception as er:
            print(er)
        return rs
class TMssql:
    def __init__(self) -> None:
        self.connections = {}

    def setConnections(self, connectionKey, host, port, uid, pwd, db, sqlPath):
        conn = None
        if connectionKey in self.connections.keys():
            conn = self.connections[connectionKey]
        else:
            conn = TMssqlConnection()
        conn.key = connectionKey
        conn.setConfig(host, port, uid, pwd, db, sqlPath)
        self.connections[connectionKey] = conn

    def routerHandlerQuery(self, result, request, router):
        try:
            ps = router.getRequestParams(request)
            dbKey = ""
            sqlKey = ""
            params = {}
            for p in ps.keys():
                if p == 'dbKey':
                    dbKey = ps["dbKey"]
                elif p == 'sqlKey':
                    sqlKey = ps["sqlKey"]
                else:
                    params[p] = ps[p]

            if dbKey in self.connections.keys():
                client = self.connections[dbKey]
                sql = client.getSql(sqlKey)
                if sql != "":
                    if len(params.keys()) == 0:
                        params = None
                    rs = client.query(sql, params)
                    result["datas"] = rs
                    result["status"] = 1
                else:
                    result["status"] = -2
                    result["error"] = "sqlKey is error"
            else:
                result["status"] = -1
                result["error"] = "dbKey is error"
        except Exception as er:
            print(er)

# meeting.xmgkfw.com:42023
# admin/Hhuc1115
# "42023:18083" #emqx-dashboard
# "42024:1883"  #emqx-http
# "42025:8081"  #emqx-https
# "42026:8083"  #emqx-ws
# "42027:8084"  #emqx-wss
class TMq :
    def __init__(self):
        self.host = "127.0.0.1"
        self.port = 31274
        self.uid = "admin"
        self.pwd = "hhuc1115"
        self.clientId = ""
        self.client = None
        self.subscribeTopics=[]
        self.actived = False
        self.events ={
            "onConnect": self.eventOnConnect,               #eventOnConnect(client, userdata, flags, rc)
            "onDisConnect": self.eventOnDisconnect,         #eventOnDisConnect(client, userdata, rc)
            "onMessage": self.eventOnMessage,               #eventOnMessage(client, userdata, topic, payload,  message)
        }

    def isConnected(self):
        res = False
        try:
            res = self.client!=None and self.actived
        except Exception as er:
            res = False
            print(er)
        return res
    def connect(self):
        try:
            userData ={"o:""mqc-2024"}
            if self.client ==None:
                self.client =  mqtt_client.Client( client_id=None, clean_session=True, userdata=userData, transport="tcp")
            else:
                self.client.reinitialise(None, clean_session=True , userdata=userData)
            self.client.username_pw_set( username=self.uid , password= self.pwd)
            self.client.on_connect = self.on_connect
            self.client.on_disconnect = self.on_disconnect
            self.client.on_message = self.on_message
            self.client.connect(host=self.host , port=self.port , keepalive=60 )
            self.actived = True
        except Exception as er :
            print(er)
        res = self.isConnected()
        return  res
    def start(self, asyncFlag):
        try:
            self.connect()
            time.sleep(1.0)
            flag = self.isConnected()
            if flag:
                if asyncFlag :
                    self.client.loop_start()
                else:
                    self.client.loop_forever()
        except Exception as er :
            print(er)
        res = self.isConnected()
        return  res
    def disConnect(self):
        try:
            pass
        except Exception as er :
            print(er)
    def sendMsg(self, topic , messagePayload):
        try:
            flag = self.isConnected()
            if flag :
                self.client.publish(topic=topic, payload=messagePayload, retain=False)
        except Exception as er :
            print(er)
    def subscribe(self, topics):
        try:
            self.client.subscribe(topics)
        except Exception as er :
            print(er)
    def on_connect(self , client, userdata, flags, rc):
        try:
            print('connect to mqtt broker', "flags=", flags, "rc=", rc)
            if rc==0 :
                self.actived = True
                if len( self.subscribeTopics)>0:
                    self.client.subscribe(self.subscribeTopics)
            else:
                self.actived = False
            if "onConnect" in self.events.keys() and  self.events["onConnect"]!=None:
                fun = self.events["onConnect"]
                fun(client,userdata, flags, rc)
        except Exception as er :
            print(er)
    def on_disconnect(self , client, userdata, rc):
        try:
            print('disconnect from mqtt broker', "rc=", rc)
            self.actived = False
            if "onDisConnect" in self.events.keys() and  self.events["onDisConnect"]!=None:
                fun = self.events["onDisConnect"]
                fun(client,userdata, rc)
        except Exception as er :
            print(er)
    def on_message(self , client, userdata, message):
        try:
            print('rec message from  mqtt broker', message)
            print('topic=', message.topic)
            print('payload=', str(message.payload) )
            if "onMessage" in self.events.keys() and  self.events["onMessage"]!=None:
                fun = self.events["onMessage"]
                fun(client,userdata, message.topic , str(message.payload) , message)
        except Exception as er :
            print(er)
    def eventOnConnect(self , client, userdata, flags, rc):
        try:
            pass
        except Exception as er :
            print(er)
    def eventOnDisconnect(self , client, userdata, rc):
        try:
            pass
        except Exception as er :
            print(er)
    def eventOnMessage(self , client, userdata, topic, payload,  message):
        try:
            pass
        except Exception as er :
            print(er)

class TInfluxDB:
    def __init__(self) -> None:
        self.host="meeting.xmgkfw.com"
        self.port = 42036
        self.token  = "Basic cm9vdDpoaHVjMTExNQ=="
        self.db = "pcs2023"
    def writeDatapoints(self , dataPoints ):
        try:
            headers = {
                "Authorization" : self.token,
                'Content-Type': 'application/json',
            }
            influxdb_url= "http://"+self.host+":"+str(self.port) + '/write?db='+self.db+'&rp=rePolicy_1h'
            resp = requests.post(url=influxdb_url , headers=headers , data=dataPoints)
            print(resp)
        except Exception as er:
            print(er)
class TModBusTcp:
    def __init__(self) -> None:
        self.masters = {}
        self.objDbConnection = TMssqlConnection()
        self.mq = TMq()
        self.notifyTopic="/ice/pcs2024"
        self.influxDB = TInfluxDB()


        self.lastTime = 0
        self.timeThreshold = 60
    def load(self, devs , tasks , regs , vars):
        try:
            for d in devs:
                master = TModBusMaster()
                master.modbusTcp = self
                master.code = d["devCode"]
                master.host = d["devHost"]
                master.port = d["devPort"]
                self.masters[master.code] = master
            for t in tasks:
                masterCode = t['devCode']
                if masterCode in self.masters.keys():
                    master = self.masters[masterCode]
                    task = TModBusTask()
                    task.master = master
                    task.taskId = t['taskId']
                    task.unitId = t['unitId']
                    task.funCode = t['funCode']
                    task.regAddr = t['regAddr']
                    task.regNum = t['regNum']
                    master.readTaskBuf.append(task)
            for r in regs:
                masterCode = r['devCode']
                if masterCode in self.masters.keys():
                    master = self.masters[masterCode]
                    reg = TModBusRegister()
                    reg.master = master
                    reg.masterCode = masterCode 
                    reg.unitId = r['unitId']
                    reg.funCode = r['funCode']
                    reg.regAddr = r['regAddr'] 
                    reg.regKey = r['regKey']
                    master.registers[reg.regKey] = reg
            for v in vars:
                masterCode = v['devCode']
                regKey = v['regKey']
                if masterCode in self.masters.keys():
                    master = self.masters[masterCode]
                    if regKey in master.registers.keys():
                        reg = master.registers[regKey]
                        var = TModBusVar()
                        var.register = reg
                        var.varId = v['varId']
                        var.varName = v['varCaption']
                        var.varType = v['varType']
                        var.bitFrom = v['bitFrom']
                        var.bitLen = v['bitLen']
                        var.rate = v['rate']
                        var.notifyType = v['notifyType']
                        var.notifyThreshold = v['notifyThreshold']
                        master.vars[var.varId] = var
                        reg.vars[var.varId] = var
                else:
                    print('err var->'+masterCode)
        except Exception as er:
            print(er)

    def loadFromDB(self):
        try:
            sql = "select * from v_sysObjs"
            rs = self.objDbConnection.query(sql,None)
            row = rs[0]
            devsJson = row['devs']
            tasksJson = row['tasks']
            regsJson = row['regs']
            varsJson = row['vars']

            devs = json.loads(devsJson)
            tasks = json.loads(tasksJson)
            regs = json.loads(regsJson)
            vars = json.loads(varsJson)

            self.load(devs,tasks,regs,vars)
        except Exception as er:
            print(er)

    def start(self):
        try:
            self.mq.start(True)
            for master in self.masters.values():
                master.startAsync()

        except Exception as er:
            print(er)
    def timeAction(self):
        try:
            nowTm = time.time()
            diffTime = nowTm - self.lastTime
            if diffTime> self.timeThreshold:
                self.lastTime = nowTm
                for master in self.masters.values():
                    if master.runningFlag:
                        self.doSaveMaster(master)
                        self.doNotifyMaster(master)
            else:
                time.sleep(0.01)
        except Exception as er:
            print(er)
    def doOnMasterRead(self, master):
        try:
            self.timeAction()
        except Exception as er :
            print(er)
    def doOnTask(self, master, task):
        try:
            #print('on task' , master , task)
            changedVars =[]
            for reg in master.registers.values():
                if reg.unitId==task.unitId and reg.funCode==task.funCode and  reg.regAddr >= task.regAddr and reg.regAddr< task.regAddr+ task.regNum:
                    for var in reg.vars.values():
                        varChanged = var.getChangedFlag()
                        if varChanged:
                            changedVars.append(var)
            if len(changedVars)>0:
                #print(changedVars)
                self.doSaveChanged(master,changedVars)
                self.doNotifyChanged(master , changedVars)


        except Exception as er :
            print(er)
    def doOnRegisterUpdate(self, register):
        try:
            #print('on register' , register.master , register)
            #self.doNotifyChanged(register)
            pass
        except Exception as er :
            print(er)
    def doOnVarUpdate(self, var):
        try:            
            pass
            #print('on var' , var.register.master , var.register , var)
        except Exception as er :
            print(er)
    def doSaveMaster(self , master):
        try:
            datas = master.getInfluxDBAllData()
            self.influxDB.writeDatapoints(datas)
        except Exception as er :
            print(er)
    def doNotifyMaster(self , master):
        try:
            topic = self.notifyTopic
            msgJson = master.getMqAllData()
            self.mq.sendMsg(topic , msgJson)
        except Exception as er :
            print(er)
    def doNotifyChanged(self, master, changedVars):
        try:
            topic = self.notifyTopic
            msgJson = master.getMqChangedVars(changedVars)
            self.mq.sendMsg(topic , msgJson)
        except Exception as er:
            print(er)
    def doSaveChanged(self , master , changedVars):
        try:
            datas = master.getInfluxDBChangedVars(changedVars)
            self.influxDB.writeDatapoints(datas)
        except Exception as er :
            print(er)
class TModBusMaster:
    def __init__(self) -> None:
        self.modbusTcp = None
        self.code = ''
        self.host = ""
        self.port = 502
        self.skt = None
        self.runningFlag = False

        self.sendNo = 0
        self.waitTime = 0.02
        self.writeTaskBuf = Queue()
        self.readTaskBuf = []
        self.readTaskIndex = 0
        self.registers={}
        self.vars ={}
    def start(self):
        try:
            flag = self.connect() 
            if flag :
                self.runningFlag = True
            while self.runningFlag and flag:
                try:
                    time.sleep(self.waitTime)
                    self.execTask()
                except Exception as err:
                    print(err)
                flag = self.isconnected()
            self.runningFlag = False
        except Exception as er :
            print(er) 
    def startAsync(self):
        try:
            execThread = threading.Thread(target= self.start, daemon=True)
            execThread.start()
        except Exception as er :
            print(er)
    def isconnected(self):
        res = False
        try:
            if self.skt!=None and not self.skt._closed:
                res = True
        except Exception as er :
            print(er)
        return res
    def connect(self):
        try:
            flag = self.isconnected()
            if flag:
                self.disconnect()                
            address = (self.host , self.port)
            self.skt = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            self.skt.settimeout(5)
            self.skt.connect(address) 
        except Exception as er :
            print(er)
        return self.isconnected()
    def disconnect(self):
        try:
            flag = self.isconnected()
            if flag:
                try:
                    self.skt.close()
                    self.skt = None
                except Exception as eer:
                    print(eer)
        except Exception as er :
            print(er)
    def execute(self, sendBytes):
        res = (False , None)
        step = -1
        try:
            self.skt.send(sendBytes)
            step = 0
            time.sleep(0.01)
            recFlagBytes = self.skt.recv(2)
            step = 1
            flag = len(recFlagBytes)==2 and recFlagBytes[0] == sendBytes[0] and recFlagBytes[1] == sendBytes[1]
            if flag:
                recHeadBytes = self.skt.recv(4)
                step = 2
                flag = len(recHeadBytes)==4
                if flag:
                    bodySize = int.from_bytes(bytearray([recHeadBytes[2],recHeadBytes[3]]), byteorder='big')
                    bodyBytes =[]
                    flag = False
                    while len(bodyBytes)< bodySize:
                        try:
                            recBytes = self.skt.recv(bodySize)
                            step = 3
                            for i in range(len(recBytes)):
                                bodyBytes.append(recBytes[i])
                        except Exception as recErr:
                            print('rec msg body error...')
                            print(recErr)
                    flag  = len(bodyBytes) == bodySize
                    res =( flag , bodyBytes)
                else:
                    pass                    
            else:
                pass
        except Exception as er :
            print(er, step)
        return res
    def read(self , unitId , funCode , regAddr , regNum):
        res = (False,None)
        try:
            sendBytes=[]
            self.sendNo = self.sendNo + 1
            if self.sendNo>65530:
                self.sendNo = 1
            sendNoBytes = int.to_bytes(self.sendNo , 2 , byteorder='big')
            regAddrBytes = int.to_bytes(regAddr , 2 , byteorder='big')
            regNumBytes = int.to_bytes(regNum , 2 , byteorder='big')
            sendBytes.append(sendNoBytes[0])
            sendBytes.append(sendNoBytes[1])
            sendBytes.append(0)
            sendBytes.append(0)
            sendBytes.append(0)
            sendBytes.append(0)
            sendBytes.append(unitId)
            sendBytes.append(funCode)
            sendBytes.append(regAddrBytes[0])
            sendBytes.append(regAddrBytes[1])
            sendBytes.append(regNumBytes[0])
            sendBytes.append(regNumBytes[1])
            msgLen = 6
            msgLenBytes = int.to_bytes(msgLen , 2 , byteorder='big')
            sendBytes[4] = msgLenBytes[0]
            sendBytes[5] = msgLenBytes[1]

            recFlag , bodyBytes = self.execute( bytearray( sendBytes))
            if recFlag :
                registers ={}
                offset = 2
                byteSize = bodyBytes[offset]
                offset = offset + 1
                if funCode in ( 0x01 , 0x02):
                    for i in range(byteSize):
                        byteData = bodyBytes[offset+i]
                        for k in range(8):
                            if i*8+k<regNum:
                                currentRegAddr = regAddr + 8 * i + k
                                val = (byteData>>k) % 2 
                                regKey = self.code+"-"+str(unitId)+"-"+str(funCode)+"-"+str(currentRegAddr)
                                regInfo = {
                                    'regKey':regKey,
                                    'regAddr' : currentRegAddr , 
                                    'h':0,
                                    'l':val,
                                }
                                registers[regKey] = regInfo 
                    res = (True , registers)
                elif funCode in ( 0x03 , 0x04):
                    index= 0 
                    while index < regNum and offset+1 < len(bodyBytes):
                        currentRegAddr = regAddr + index
                        regKey = self.code+"-"+str(unitId)+"-"+str(funCode)+"-"+str(currentRegAddr)
                        regInfo = {
                            'regKey':regKey,
                            'regAddr' : currentRegAddr , 
                            'h':bodyBytes[offset],
                            'l':bodyBytes[offset+1]
                        }
                        offset = offset + 2
                        registers[regKey] = regInfo
                        index = index + 1
                    res = (True , registers)
        except Exception as er :
            print(er)
        return res
    def setCoil(self , unitId , regAddr , coilVal ):
        res = (False,None)
        try: 
            self.sendNo = self.sendNo + 1
            sendNoBytes = int.to_bytes(self.sendNo , 2 , byteorder='big')
            regAddrBytes = int.to_bytes(regAddr , 2 , byteorder='big')
            sendBytes=[
                sendNoBytes[0],sendNoBytes[1],
                0,0,
                0,0x06,
                unitId,
                0x01 ,
                regAddrBytes[0],regAddrBytes[1]
            ]
            if coilVal ==0 :
                sendBytes.append(0)
            else:
                sendBytes.append[0xff]
            sendBytes.append(0)
            recFlag , bodyBytes = self.execute( bytearray( sendBytes))
            res =( recFlag , bodyBytes)
        except Exception as er :
            print(er)
        return res
    def writeCoilRegisters(self , unitId , regAddr , coilValList ):
        res = (False,None)
        try: 
            self.sendNo = self.sendNo + 1
            sendNoBytes = int.to_bytes(self.sendNo , 2 , byteorder='big')
            regAddrBytes = int.to_bytes(regAddr , 2 , byteorder='big')
            byteSize = math.ceil(len(coilValList) * 0.125)
            dataLen = byteSize + 5
            sendBytes=[
                sendNoBytes[0],sendNoBytes[1],
                0,0,
                0,dataLen,
                unitId,
                0x0f ,
                regAddrBytes[0],regAddrBytes[1],
                byteSize
            ]
            for i in range(byteSize):
                item = 0
                for k in range(8):
                    index = i * 8 + k
                    val = coilValList[index]
                    item= item + val<<k
                sendBytes.append(item)
            recFlag , bodyBytes = self.execute( bytearray( sendBytes))
            res =( recFlag , bodyBytes)
        except Exception as er :
            print(er)
        return res
    def writeReg0x06(self , unitId , regAddr , regVal ):
        res = (False,None)
        try: 
            self.sendNo = self.sendNo + 1
            sendNoBytes = int.to_bytes(self.sendNo , 2 , byteorder='big')
            regAddrBytes = int.to_bytes(regAddr , 2 , byteorder='big')
            byteDataItem = int.to_bytes(regVal , 2 , byteorder='big')
            sendBytes=[
                sendNoBytes[0],sendNoBytes[1],
                0,0,
                0,6,
                unitId,
                0x06 ,
                regAddrBytes[0],regAddrBytes[1],
                byteDataItem[0],byteDataItem[1]
            ]
            recFlag , bodyBytes = self.execute( bytearray( sendBytes))
            res =( recFlag , bodyBytes)
        except Exception as er :
            print(er)
        return res
    def writeRegisters0x10(self , unitId , regAddr , regVals):
        res = (False,None)
        try: 
            self.sendNo = self.sendNo + 1
            sendNoBytes = int.to_bytes(self.sendNo , 2 , byteorder='big')
            regAddrBytes = int.to_bytes(regAddr , 2 , byteorder='big')
            byteSize = 2*len(regVals)
            dataLen = byteSize + 5
            sendBytes=[
                sendNoBytes[0],sendNoBytes[1],
                0,0,
                0,dataLen,
                unitId,
                0x10 ,
                regAddrBytes[0],regAddrBytes[1],
                byteSize
            ]
            for i in range(byteSize):
                val = regVals[i]
                byteDataItem = int.to_bytes(val , 2 , byteorder='big')
                sendBytes.append(byteDataItem[0])
                sendBytes.append(byteDataItem[1])
            recFlag , bodyBytes = self.execute( bytearray( sendBytes))
            res =( recFlag , bodyBytes)
        except Exception as er :
            print(er)
        return res
#---------------------
    def getCurrentTask(self ):
        res = None
        try: 
            task=None
            if self.writeTaskBuf.empty():
                self.readTaskIndex = self.readTaskIndex + 1
                if self.readTaskIndex>= len(self.readTaskBuf):
                    self.readTaskIndex = 0 
                task = self.readTaskBuf[self.readTaskIndex]
            else:
                task = self.writeTaskBuf.get()
            res = task
        except Exception as er: 
            print(er)
        return res
    def execTask(self):
        try:
            task = self.getCurrentTask()
            flag = False
            bodyBytes = None
            if task.funCode <= 0x04:
                flag , registers = self.read( task.unitId , task.funCode , task.regAddr , task.regNum)
                #self.modbusTcp.doOnTask(self, task)
                if flag :
                    for r in registers.values():
                        if r['regKey']  in self.registers.keys():
                            reg = self.registers[r['regKey']]
                            reg.h = r['h']
                            reg.l = r['l']
                            reg.decode()
                            #regVars = reg.vars
                            #print(regVars)
                    self.modbusTcp.doOnTask(self, task)
                    if self.readTaskIndex +1 == len( self.readTaskBuf):
                        self.modbusTcp.doOnMasterRead(self)
            elif task.funCode == 0x05:
                flag , bodyBytes = self.setCoil(task.unitId , task.regAddr , task.writeVals[0])
                self.logWrite(bodyBytes)
            elif task.funCode == 0x06:
                flag , bodyBytes = self.writeReg0x06(task.unitId , task.regAddr , task.writeVals[0])
                self.logWrite(bodyBytes)
            elif task.funCode == 0x0f:
                flag , bodyBytes = self.writeCoilRegisters(task.unitId , task.regAddr , task.writeVals )
                self.logWrite(bodyBytes)
            elif task.funCode == 0x10:
                flag , bodyBytes = self.writeRegisters0x10(task.unitId , task.regAddr , task.writeVals ) 
                self.logWrite(bodyBytes)
        except Exception as er:
            print(er) 
    def notifyAllVars(self ):
        try: 
            print('---------------- loop notify ----------------')
        except Exception as er: 
            print(er)
    def notifyCoil(self , var):
        try: 
            pass
        except Exception as er: 
            print(er)
    def logWrite(self , bodySize):
        res = None
        try: 
            pass
        except Exception as er: 
            print(er)
        return res    
    def getInfluxDBAllData(self):
        res =""
        try:
            res = "td_"+self.code +",master="+ self.code+" v=0"
            for var in self.vars.values():
                fk = 'v_'+str(var.varId)
                res = res + ","+fk+"="+str(var.varVal)
        except Exception as er:
            print(er)
        return  res
    def getInfluxDBChangedVars(self, vars):
        res =""
        try:
            for var in vars:
                item =res + "td_log,master="+self.code+",unitid="+str(var.register.unitId)+",funcode="+str(var.register.funCode)+",varid="+str(var.varId)
                item = item +" val="+str(var.varVal)+"\n"
                res = res + item
        except Exception as er:
            print(er)
        return  res
    def getMqAllData(self):
        res = {
            "master":self.code,
            "time": time.time(),
            "reason":"all",
            "items":[]
        }
        try:
            for var in self.vars.values():
                item={
                    "varId": var.varId,
                    "funCode": var.register.funCode,
                    "unitId": var.register.unitId,
                    "varName":var.varName ,
                    "varVal": var.varVal
                }
                res["items"].append(item)
        except Exception as er:
            print(er)
        return  json.dumps(res)
    def getMqChangedVars(self, vars):
        res = {
            "master":self.code,
            "time": time.time(),
            "reason":"changed",
            "items":[]
        }
        try:
            for var in vars:
                item={
                    "varId": var.varId,
                    "funCode": var.register.funCode,
                    "unitId": var.register.unitId,
                    "varName":var.varName ,
                    "varVal": var.varVal
                }
                res["items"].append(item)
        except Exception as er:
            print(er)
        return  json.dumps(res)

class TModBusTask:
    def __init__(self) -> None:
        self.master = None
        self.taskId = 0 
        self.unitId = 0
        self.funCode = 0
        self.regAddr = 0 
        self.regNum = 0
        self.writeVals=[]
    def getSendCmdBytes(self, msgId):
        res = []
        try: 
            task = self   
            if task.funCode in [0x01,0x02,0x03,0x04]:
                msgIdBytes = int.to_bytes(msgId , 2 , byteorder='big')
                regAddrBytes = int.to_bytes(task.regAddr , 2 , byteorder='big')
                regNumBytes = int.to_bytes(task.regNum , 2 , byteorder='big')
                funCode = task.funCode
                unitId = task.unitId
                res= [msgIdBytes[0],msgIdBytes[1],0,0,0,6, unitId ,funCode,regAddrBytes[0],regAddrBytes[1],regNumBytes[0],regNumBytes[1]]
            elif task.funCode in [0x05]:
                msgIdBytes = int.to_bytes(msgId , 2 , byteorder='big')
                regAddrBytes = int.to_bytes(task.regAddr , 2 , byteorder='big')
                valBytes = bytearray([0,0])
                if task.writeVals[0]!=0:
                    valBytes[0] = 0xff
                funCode = task.funCode
                unitId = task.unitId
                res= [msgIdBytes[0],msgIdBytes[1],0,0,0,6, unitId ,funCode,regAddrBytes[0],regAddrBytes[1],valBytes[0],valBytes[1]]
            elif task.funCode in [0x06]:
                msgIdBytes = int.to_bytes(msgId , 2 , byteorder='big')
                regAddrBytes = int.to_bytes(task.regAddr , 2 , byteorder='big')
                valBytes = int.to_bytes(task.writeVals[0] , 2 , byteorder='big') 
                funCode = task.funCode
                unitId = task.unitId
                res= [msgIdBytes[0],msgIdBytes[1],0,0,0,6, unitId ,funCode,regAddrBytes[0],regAddrBytes[1],valBytes[0],valBytes[1]]
            elif task.funCode in [0x10]:
                task.regNum = len( task.writeVals)
                msgIdBytes = int.to_bytes(msgId , 2 , byteorder='big')
                regAddrBytes = int.to_bytes(task.regAddr , 2 , byteorder='big')
                regNumBytes = int.to_bytes(task.regNum , 2 , byteorder='big')
                byteSize = len(task.writeVals)*2
                bodySize = byteSize + 1 + 4 + 2 
                bodySizeBytes = int.to_bytes(bodySize , 2 , byteorder='big')
                funCode = task.funCode
                unitId = task.unitId
                res= [msgIdBytes[0],msgIdBytes[1],0,0,bodySizeBytes[0],bodySizeBytes[1], unitId ,funCode,regAddrBytes[0],regAddrBytes[1],regNumBytes[0],regNumBytes[1], byteSize]
                for i in range(task.regNum):
                    val = task.writeVals[i]
                    valBytes = int.to_bytes(val , 2 , byteorder='big')
                    res.append(valBytes[0])
                    res.append(valBytes[1])
        except Exception as er:
            print(er)
        return bytearray(res)
class TModBusRegister:
    def __init__(self) -> None:
        self.master = None
        self.regKey = ""
        self.masterCode = ""
        self.unitId = 0
        self.regAddr = 0  
        self.vars = {}
        self.h = 0 
        self.l = 0 
    def decode(self ):
        #print( self.regAddr , self.h , self.l)
        try:
            for var in self.vars.values():
                var.update()
                #print(var.varId , var.changed , var.updateTime)
            self.master.modbusTcp.doOnRegisterUpdate(self)
        except Exception as er:
            print(er)
class TModBusVar:
    def __init__(self) -> None:
        self.register = None
        self.varId = 0
        self.varName = ""
        self.varType = "V01"
        self.bitFrom = -1
        self.bitLen = 0 
        self.rate = 0 
        self.notifyType = 'N01'
        self.notifyThreshold = 0 
                
        self.varVal = 0         
        self.updateTime = 0
        self.oldVal = 0
 
    def update(self ):
        try:
            val = 0
            if( self.varType=='V01'):
                bitPos = self.bitFrom 
                byteData = self.register.l
                if bitPos>7:
                    bitPos = bitPos-8
                    byteData = self.register.h
                val = (byteData>>bitPos) % 2
            elif( self.varType=='V02'):
                byteData = self.register.l
                bitPos = self.bitFrom 
                if bitPos>=8:
                    bitPos = bitPos - 8
                    byteData = self.register.h
                mask = ((1<<self.bitLen) -1 )<<bitPos
                val = byteData & mask
            elif( self.varType=='V03'):
                val = int.from_bytes(bytearray([self.register.h , self.register.l]), byteorder='big', signed=True)
            elif( self.varType=='V04'):
                val = int.from_bytes(bytearray([self.register.h , self.register.l]), byteorder='big', signed=False)
            elif( self.varType=='V05'):
                regNext = self.register.regKey.split('-')
                regAddr = self.register.regAddr + 1
                nextRegKey = regNext[0]+"-"+regNext[1]+"-"+regNext[2]+"-"+str(regAddr)
                regs = self.register
                if nextRegKey in  regs.keys():
                    nextReg = regs[nextRegKey]
                    dataBytes =bytearray([self.reg.h,self.reg.l,nextReg.h, nextReg.l])
                    val = int.from_bytes(dataBytes, byteorder='big', signed=False)
            elif( self.varType=='V06'):
                val = self.register.h
            elif( self.varType=='V07'):
                val = self.register.l
            elif( self.varType=='V08'):
                val = self.register.l
            self.oldVal = self.varVal
            self.varVal = val
            self.updateTime = time.time()
            #self.setVal(val)
            #print( self.varId, self.varName , self.varVal)
        except Exception as er:
            print(er)

    def setVal(self, val):
        try:
            changed = False
            nowTm = time.time()
            if val!=self.varVal:
                self.oldVal = self.varVal
                self.varVal = val
            if self.updateTime ==0 :
                changed = True
            else:
                if self.varType == 'N01' and self.oldVal!=self.varVal:
                    changed = True
                elif self.varType =='N02' :
                    if self.oldVal == 0 :
                        changed = True
                    else:
                        diffVal = abs(self.varVal - self.oldVal)
                        diffRate = diffVal*1.0/abs(self.oldVal)
                        changed = diffRate >= self.notifyThreshold
                elif self.varType =='N03' :
                    if self.oldVal == 0 :
                        changed = True
                    else:
                        diffVal = abs(self.varVal - self.oldVal)
                        changed = diffVal >= self.notifyThreshold
            if changed :
                self.updateTime = nowTm
            self.changed = changed
            if self.changed:
                print('var changed :', self.varName, self.oldVal, '->', self.varVal)
        except Exception as er:
            print(er)
    def getChangedFlag(self):
        res = False
        try:
            changed = False
            nowTm = time.time()
            if self.oldVal==self.varVal:
                changed = False
            else:
                if self.varType == 'N01' and self.oldVal!=self.varVal:
                    changed = True
                elif self.varType =='N02' :
                    if self.oldVal == 0 :
                        changed = True
                    else:
                        diffVal = abs(self.varVal - self.oldVal)
                        diffRate = diffVal*1.0/abs(self.oldVal)
                        changed = diffRate >= self.notifyThreshold
                elif self.varType =='N03' :
                    if self.oldVal == 0 :
                        changed = True
                    else:
                        diffVal = abs(self.varVal - self.oldVal)
                        changed = diffVal >= self.notifyThreshold
            res = changed
        except Exception as er:
            res = False
            print(er)
        return  res


m = TModBusTcp()
#m.load(sysObjs.devs , sysObjs.tasks , sysObjs.regs , sysObjs.vars);
m.loadFromDB()
#m.masters['pcs'].start()
m.start()
while 1>0:
    time.sleep(1)